import { DocumentEventCenter } from "./DocumentEventCenter";
import { IShaderBase } from "./IShaderBase";
import { Keyboard } from "./Keyboard";
import { ShaderTool } from "./ShaderTool";
import { Vector3 } from "./math/Vector3";

export class BaseCamera implements IShaderBase {


    eyeVec3: Vector3;
    lookVec3: Vector3;

    protected viewMatrix: Matrix4;
    protected projectMatrix: Matrix4;


    private _isMouseDown: boolean;

    private _needUpdateRender: boolean; // 需要更新渲染

    fovy: number = 60;
    aspect: number = 1.0;
    near: number = 0.1;
    far: number = 100.0;
    angleY: number = 0;
    angleX: number = 0;

    /** 是否旋转模型 */
    public rotaModule: boolean = false;

    init(gl: WebGL2RenderingContext | WebGLRenderingContext) {

        this.eyeVec3 = new Vector3(0.0, 0.0, 5.0);
        this.lookVec3 = new Vector3(0.0, 0.0, -100.0);
        this.viewMatrix = new Matrix4();
        this.projectMatrix = new Matrix4();

        this._isMouseDown = false;

        DocumentEventCenter.regMouseDown(this, this.onMouseDown, [gl]);
        DocumentEventCenter.regMouseMove(this, this.onMouseMove, [gl]);
        DocumentEventCenter.regMouseUp(this, this.onMouseUp, [gl]);

        DocumentEventCenter.regKeyDown(this, this.onKeyDown, [gl]);
        DocumentEventCenter.regKeyUp(this, this.onKeyUp, [gl]);
        this.needUpdateRender = true;
        DocumentEventCenter.regEvent(DocumentEventCenter.updateRenderFlag, this, this._updateRenderFlag,);

    }

    private _updateRenderFlag() {
        this.needUpdateRender = true;
    }



    onKeyDown(gl: WebGL2RenderingContext | WebGLRenderingContext, ev: KeyboardEvent) {
        switch (ev.keyCode) {
            case Keyboard.W:
                this.eyeVec3.z -= 0.01;
                this.needUpdateRender = true;
                break;
            case Keyboard.S:
                this.eyeVec3.z += 0.01;
                this.needUpdateRender = true;
                break;
        }
        DocumentEventCenter.sendEvent(DocumentEventCenter.keyDown, [ev]);
    }

    onKeyUp(gl: WebGL2RenderingContext | WebGLRenderingContext, ev: KeyboardEvent) {

    }

    onMouseDown(gl: WebGL2RenderingContext | WebGLRenderingContext, ev: MouseEvent) {
        this._isMouseDown = true;
    }

    onMouseMove(gl: WebGL2RenderingContext | WebGLRenderingContext, ev: MouseEvent) {
        if (this._isMouseDown) {
            this.needUpdateRender = true;
            let rotay = ev.movementX;
            this.angleY += rotay;
            this.angleX += ev.movementY;

        }
    }

    onMouseUp(gl: WebGL2RenderingContext | WebGLRenderingContext, ev: MouseEvent) {
        this._isMouseDown = false;
    }

    inputBlur(text: string): void {
        if (text) {
            ShaderTool.setProperty(text, this);
            this.needUpdateRender = true;
        }
    }

    public update() {
        if (!this._needUpdateRender) return this._needUpdateRender;
        this.needUpdateRender = false;
        this.viewMatrix.setLookAt(
            this.eyeVec3.x, this.eyeVec3.y, this.eyeVec3.z,
            this.lookVec3.x, this.lookVec3.y, this.lookVec3.z,
            Vector3.Up.x, Vector3.Up.y, Vector3.Up.z
        );
        if (!this.rotaModule) {
            this.viewMatrix.rotate(this.angleY, 0.0, 1.0, 0.0).rotate(this.angleX, 1.0, 0.0, 0.0);
        }
        this.projectMatrix.setPerspective(
            this.fovy,
            this.aspect,
            this.near,
            this.far
        );


        console.log(`eye.x:${this.eyeVec3.x}  eye.y:${this.eyeVec3.y}  eye.z:${this.eyeVec3.z}  `);

        return true;
    }

    public getMvpMatrix(moduleMatrix: Matrix4, mvpMatrix:Matrix4): Matrix4 {
        mvpMatrix ||= new Matrix4();
        mvpMatrix.set(this.projectMatrix).multiply(this.viewMatrix).multiply(moduleMatrix);
        return mvpMatrix;
    }

    set needUpdateRender(value: boolean) {
        this._needUpdateRender = value;
    }

    get needUpdateRender(): boolean {
        return this._needUpdateRender;
    }

    draw(gl: WebGL2RenderingContext | WebGLRenderingContext): void {

    }
}